package mviewer.model3dLoader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;
import mviewer.types.Model3d;
import mviewer.types.IModel3d;
import mviewer.types.IModel3dBuilder;
import mviewer.types.Material;
import mviewer.types.VectorData;

public class PlgModelLoader implements IModel3dLoader {

	@Override
	public boolean supports(String file) {
		return file.endsWith(".plg");
	}

	@Override
	public IModel3d loadModel(String file)
			throws FileNotFoundException, IOException {
		IModel3dBuilder modelBuilder;
		FileReader reader = new FileReader(file);
		StreamTokenizer st = new StreamTokenizer(reader);
		try {
			st.nextToken();
			int vertexCount = (int)st.nval;
			st.nextToken();
			int polygonCount = (int)st.nval;
			modelBuilder = new Model3d(file, vertexCount, polygonCount);
			st.nextToken();
			Material[] materials = new Material[(int)st.nval];

			readVertices(st, modelBuilder, vertexCount);
			readPolygons(st, modelBuilder, polygonCount, materials);
			readColors(st,	 modelBuilder, materials);
		} catch(NumberFormatException e) {
			throw new UnsupportedOperationException(
					"Unsupported file format. PLG expected.");
		} catch(IOException e) {
			throw new UnsupportedOperationException(
					"Unsupported file format. PLG expected.");
		}
		reader.close();
		modelBuilder.apply();
		return (IModel3d)modelBuilder;
	}

	private void readVertices(StreamTokenizer st, IModel3dBuilder builder,
			int vertexCount) throws IOException {
		for (int i = 0; i < vertexCount; i++) {
			st.nextToken();
			float x = (float)st.nval;
			st.nextToken();
			float y = (float)st.nval;
			st.nextToken();
			float z = (float)st.nval;

			builder.appendVertex(x, y, z);
		}
	}

	private void readPolygons(StreamTokenizer st, IModel3dBuilder builder,
			int polygonCount, Material[] materials) throws IOException {
		int[] v;
		for (int i = 0; i < polygonCount; i++) {
			v = new int[3];
			st.nextToken();
			v[0] = (int)st.nval - 1;
			st.nextToken();
			v[1] = (int)st.nval - 1;
			st.nextToken();
			v[2] = (int)st.nval - 1;
			st.nextToken();
			int mi = (int) st.nval - 1;
			if (materials[mi] == null)
				materials[mi] = new Material(); // create material

			builder.setMaterial(materials[mi]);
			builder.appendPolygon(v); // applies model material by default
		}
	}

	private void readColors(StreamTokenizer st, IModel3dBuilder builder,
			Material[] materials) throws IOException {
		for (int i = 0; i < materials.length; i++) {
			st.nextToken();
			float r = (float)st.nval;
			st.nextToken();
			float g = (float)st.nval;
			st.nextToken();
			float b = (float)st.nval;
			st.nextToken();
			materials[i].setDiffuseColor(new VectorData(r, g, b));
			materials[i].setAmbientColor(new VectorData(0.5f * r, 0.5f * g, 0.5f * b));
		}
	}
}